#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "NamedElement.h"
#include "Namespace.h"
#include "RedefinableElement.h"
#include "TransitionKind.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Behavior;
class Classifier;
class Constraint;
class RedefinableElement;
class Region;
class StateMachine;
class Trigger;
class Vertex;

/// <summary>
/// Transition
/// A Transition represents an arc between exactly one source Vertex and exactly one
/// Target vertex (the source and targets may be the same Vertex). It may form part
/// of a compound transition, which takes the StateMachine from one steady State
/// configuration to another, representing the full response of the StateMachine to
/// an occurrence of an Event that triggered it.
/// </summary>
class UMLMODEL_EXPORT Transition : public NamedElement, public Namespace, public RedefinableElement {

public: // Constructors and destructors
    explicit Transition(const QString& umlType="uml::Transition");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// containingStateMachine
    /// The query containingStateMachine() returns the StateMachine that contains the
    /// Transition either directly or transitively.
    /// </summary>
    virtual shared_ptr<StateMachine> containingStateMachine() const;

    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies that a redefining Transition is
    /// consistent with a redefined Transition provided that the redefining Transition
    /// has the following relation to the redefined Transition: A redefining Transition
    /// redefines all properties of the corresponding redefined Transition except the
    /// source State and the Trigger.
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

public: // Properties
    /// <summary>
    /// container getter
    /// Designates the Region that owns this Transition.
    /// </summary>
    shared_ptr<Region> container() const;

    /// <summary>
    /// container setter
    /// Designates the Region that owns this Transition.
    /// </summary>
    void setContainer(shared_ptr<Region> value);

    /// <summary>
    /// effect getter
    /// Specifies an optional behavior to be performed when the Transition fires.
    /// </summary>
    shared_ptr<Behavior> effect() const;

    /// <summary>
    /// effect setter
    /// Specifies an optional behavior to be performed when the Transition fires.
    /// </summary>
    void setEffect(shared_ptr<Behavior> value);

    /// <summary>
    /// guard getter
    /// A guard is a Constraint that provides a fine-grained control over the firing of
    /// the Transition. The guard is evaluated when an Event occurrence is dispatched by
    /// the StateMachine. If the guard is true at that time, the Transition may be
    /// enabled, otherwise, it is disabled. Guards should be pure expressions without
    /// side effects. Guard expressions with side effects are ill formed.
    /// </summary>
    shared_ptr<Constraint> guard() const;

    /// <summary>
    /// guard setter
    /// A guard is a Constraint that provides a fine-grained control over the firing of
    /// the Transition. The guard is evaluated when an Event occurrence is dispatched by
    /// the StateMachine. If the guard is true at that time, the Transition may be
    /// enabled, otherwise, it is disabled. Guards should be pure expressions without
    /// side effects. Guard expressions with side effects are ill formed.
    /// </summary>
    void setGuard(shared_ptr<Constraint> value);

    /// <summary>
    /// kind getter
    /// Indicates the precise type of the Transition.
    /// </summary>
    TransitionKind kind() const;

    /// <summary>
    /// kind setter
    /// Indicates the precise type of the Transition.
    /// </summary>
    void setKind(TransitionKind value);

    /// <summary>
    /// redefinedTransition getter
    /// The Transition that is redefined by this Transition.
    /// </summary>
    shared_ptr<Transition> redefinedTransition() const;

    /// <summary>
    /// redefinedTransition setter
    /// The Transition that is redefined by this Transition.
    /// </summary>
    void setRedefinedTransition(shared_ptr<Transition> value);

    /// <summary>
    /// redefinitionContext getter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext() const;

    /// <summary>
    /// redefinitionContext setter
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    void setRedefinitionContext(shared_ptr<Classifier> value);

    /// <summary>
    /// source getter
    /// Designates the originating Vertex (State or Pseudostate) of the Transition.
    /// </summary>
    shared_ptr<Vertex> source() const;

    /// <summary>
    /// source setter
    /// Designates the originating Vertex (State or Pseudostate) of the Transition.
    /// </summary>
    void setSource(shared_ptr<Vertex> value);

    /// <summary>
    /// target getter
    /// Designates the target Vertex that is reached when the Transition is taken.
    /// </summary>
    shared_ptr<Vertex> target() const;

    /// <summary>
    /// target setter
    /// Designates the target Vertex that is reached when the Transition is taken.
    /// </summary>
    void setTarget(shared_ptr<Vertex> value);

    /// <summary>
    /// triggers getter
    /// Specifies the Triggers that may fire the transition.
    /// </summary>
    vector<shared_ptr<Trigger>>& triggers();

private: // Fields
    /// <summary>
    /// container
    /// Designates the Region that owns this Transition.
    /// </summary>
    shared_ptr<Region> container_;

    /// <summary>
    /// effect
    /// Specifies an optional behavior to be performed when the Transition fires.
    /// </summary>
    shared_ptr<Behavior> effect_;

    /// <summary>
    /// guard
    /// A guard is a Constraint that provides a fine-grained control over the firing of
    /// the Transition. The guard is evaluated when an Event occurrence is dispatched by
    /// the StateMachine. If the guard is true at that time, the Transition may be
    /// enabled, otherwise, it is disabled. Guards should be pure expressions without
    /// side effects. Guard expressions with side effects are ill formed.
    /// </summary>
    shared_ptr<Constraint> guard_;

    /// <summary>
    /// kind
    /// Indicates the precise type of the Transition.
    /// </summary>
    TransitionKind kind_ = TransitionKind::kexternal;

    /// <summary>
    /// redefinedTransition
    /// The Transition that is redefined by this Transition.
    /// </summary>
    shared_ptr<Transition> redefinedTransition_;

    /// <summary>
    /// redefinitionContext
    /// References the Classifier in which context this element may be redefined.
    /// </summary>
    shared_ptr<Classifier> redefinitionContext_;

    /// <summary>
    /// source
    /// Designates the originating Vertex (State or Pseudostate) of the Transition.
    /// </summary>
    shared_ptr<Vertex> source_;

    /// <summary>
    /// target
    /// Designates the target Vertex that is reached when the Transition is taken.
    /// </summary>
    shared_ptr<Vertex> target_;

    /// <summary>
    /// triggers
    /// Specifies the Triggers that may fire the transition.
    /// </summary>
    vector<shared_ptr<Trigger>> triggers_;

};

} // namespace uml
